/*
 * Copyright (c) 2021 Chipsea Technologies (Shenzhen) Corp., Ltd. All rights reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef _WIFI_HOST_WPA_H
#define _WIFI_HOST_WPA_H

#include "wifi_host.h"

/**
 * WPA events.\n
 * Events are generated by a WPA task be calling @ref fhost_wpa_send_event.
 * They are then processed by the function @ref fhost_wpa_event_process and the callbacks
 * registered with @ref fhost_wpa_cb_register
 */
enum fhost_wpa_event {
    /**
     * - desc: WPA task ends
     * - data_type: int
     * - data_value: contains wpa task exit code
     */
    FHOST_WPA_EXIT = 1,
    /**
     * - desc: WPA started (i.e. initialization was sucessful)
     * - data_type: int
     * - data_value: contains UDP control port
     */
    FHOST_WPA_STARTED,
    /**
     * - desc: Connection to an Access Point is completed
     * - data_type: None
     * - data_value: None
     */
    FHOST_WPA_CONNECTED,
    /**
     * - desc: Connection to an Access Point is terminated
     * - data_type: None
     * - data_value: None
     */
    FHOST_WPA_DISCONNECTED,
    FHOST_WPA_LAST,
};

/**
 * wpa_supplicant state.\n
 * The WPA task FSM looks like:
 * @verbatim
 +---------+        +---------------+        +-----------+
 | STOPPED | <----> | NOT_CONNECTED | <----> | CONNECTED |
 +---------+        +---------------+        +-----------+
 @endverbatim
 */
enum fhost_wpa_state
{
    /// wpa_supplicant is not running
    FHOST_WPA_STATE_STOPPED,
    /// wpa_supplicant is running but not connected
    FHOST_WPA_STATE_NOT_CONNECTED,
    /// wpa_supplicant is running and connected
    FHOST_WPA_STATE_CONNECTED,
};

/**
 * Configuration of wpa_supplicant task
 */
struct fhost_wpa_config {
    /**
     * Name of the interface
     */
    char iface_name[NET_AL_MAX_IFNAME];
    /**
     * Index, at FHOST level, of the interface
     */
    int fhost_vif_idx;
    /**
     * Pointer to a configuration buffer (may be null)
     */
    char *iface_conf_buffer;
    /**
     * Name of the control interface:
     * - NULL for no control interface
     * - UDP  for control interface via UDP socket
     */
    char *ctrl_itf;
};

/// WPA event message callback type
typedef void (*fhost_wpa_cb_t) (int fhost_vif_idx, enum fhost_wpa_event event,
                                void *event_params, void *arg);

/**
 ****************************************************************************************
 * @brief Init global variables used by fhost_wpa_xxxx functions
 ****************************************************************************************
 */
void fhost_wpa_init(void);

/**
 ****************************************************************************************
 * @brief Start wpa_supplicant task for an interface
 *
 * This function is blocking until wpa_supplicant task is fully initialized (or an error
 * is returned during task initialization).
 * Only one wpa supplicant task can be started per interface.
 * @note If the AP configuration is already known @ref fhost_wpa_create_network can be
 * used instead.
 *
 * @param[in] fhost_vif_idx  Index of the FHOST interface
 * @param[in] config         wpa_supplicant configuration (May be NULL, not yet supported)
 *
 * @return 0 if wpa_supplicant has been successfully initialized and !=0 otherwise.
 ****************************************************************************************
 */
int fhost_wpa_start(int fhost_vif_idx, char *config);

/**
 ****************************************************************************************
 * @brief End wpa_supplicant task for an interface
 *
 * This function is blocking until wpa_supplicant task is deleted.
 *
 * @param[in] fhost_vif_idx  Index of the FHOST interface
 *
 * @return 0 if wpa_supplicant has been successfully closed and !=0 otherwise.
 ****************************************************************************************
 */
int fhost_wpa_end(int fhost_vif_idx);

/**
 ****************************************************************************************
 * @brief Retrieve the wpa task state
 *
 * @param[in] fhost_vif_idx  Index of the FHOST interface
 *
 * @return current wpa_supplicant state for the interface
 ****************************************************************************************
 */
enum fhost_wpa_state fhost_wpa_get_state(int fhost_vif_idx);

/**
 ****************************************************************************************
 * @brief Register a callback for a set of WPA events
 *
 * The callback will be called with the registered argument as WPA task emits one of the
 * event in @p events bit-field.
 * Up to @ref FHOST_WPA_EVENT_CB_CNT callbacks can be registered for one interface.
 *
 * @note Currently there is no synchronization between callback registration and event
 * processing and it is assumed that cb will be registered before WPA task can emit any
 * of the events.
 *
 * @note Callbacks are called in the context of the WPA task so is cannot block upon WPA
 * task (e.g. it cannot send WPA command).
 *
 * @param[in] fhost_vif_idx  Index of the FHOST interface
 * @param[in] events         Bit-field of events associated to the callback.
 * @param[in] cb_func        Callback function
 * @param[in] cb_arg         Callback function private argument
 *
 * @return 0 if callback has been successfully registered and !=0 otherwise.
 ****************************************************************************************
 */
int fhost_wpa_cb_register(int fhost_vif_idx, int events, fhost_wpa_cb_t cb_func, void *cb_arg);

/**
 ****************************************************************************************
 * @brief Unregister a callback for WPA events
 *
 * Does nothing if callback wasn't previously registered.
 *
 * @param[in] fhost_vif_idx  Index of the FHOST interface
 * @param[in] cb_func        Callback functions
 *
 * @return 0 if callback has been successfully unregistered and !=0 otherwise.
 ****************************************************************************************
 */
int fhost_wpa_cb_unregister(int fhost_vif_idx, fhost_wpa_cb_t cb_func);

/**
 ****************************************************************************************
 * @brief Send a WPA event to the control task
 *
 * Emit a WPA event. This should only be used by a WPA task, and the event will be
 * processed in the context of the calling task.
 * @note For now, parameters are only 32bits and then passed as the address.
 *
 * @param[in] event        WPA event id
 * @param[in] param        Event parameters
 * @param[in] param_len    Length, in bytes, of the parameters
 * @param[in] fhost_vif_idx Index of the FHOST interface
 *
 * @return 0 on success and != 0 if error occured.
 ****************************************************************************************
 */
int fhost_wpa_send_event(enum fhost_wpa_event event, void *param, int param_len, int fhost_vif_idx);

/**
 ****************************************************************************************
 * @brief Send command to the wpa_supplicant task associated and retrieve the response
 *
 * This function is blocking until the command is executed by wpa_supplicant.
 * If no wpa_supplicant has been started for the requested interface or if it has been
 * started without ctrl interface this function immediately returns an error.
 *
 * A timeout of @p timeout_ms is set for the response, meaning that if wpa_supplicant
 * doesn't respond before the function will return an error.
 *
 * The response is truncated to fit inside the provided buffer, and if response is not
 * needed the parameter @p resp can be NULL. In any case (i.e. even if no response buffer
 * is provided) if the response starts with the string "FAIL" the functions returns 1.
 *
 * @param[in]     fhost_vif_idx  Index of the FHOST interface.
 * @param[in]     resp_buf       Buffer to retrieve the response.
 * @param[in,out] resp_buf_len   Size, in bytes, of the response buffer.
 *                               If no error is reported, it is updated with the size
 *                               actually written in the response buffer.
 * @param[in]     timeout_ms     Timeout, in ms, allowed to the wpa_supplicant task to
 *                               execute the command (<0 means wait forever).
 * @param[in]     fmt            Command to send to the wpa_supplicant task. The command
 *                               is first formatted using optional parameters.
 *
 * @return <0 if an error occurred (invalid parameter, timeout, ...), 1 if the response
 * starts with "FAIL" and 0 otherwise.
 ****************************************************************************************
 */
int fhost_wpa_execute_cmd(int fhost_vif_idx, char *resp_buf, int *resp_buf_len,
                          int timeout_ms, const char *fmt, ...);

/**
 ****************************************************************************************
 * @brief Start wpa_supplicant and create a network configuration.
 *
 * This function should be used instead of @ref fhost_wpa_start to start the
 * wpa_supplicant with a network already configured.
 * The network configuration is a string in which each token separated by a ';' is used
 * as parameter to 'SET_NETWORK' command.
 * If @p enable is true then the function is blocking until connection to the network.
 * (see @ref fhost_wpa_enable_network for details)
 *
 * @param[in] fhost_vif_idx  Index of the FHOST interface.
 * @param[in] net_cfg        Network configuration.
 * @param[in] enable         Whether network should be enabled.
 * @param[in] timeout_ms     Timeout, in ms, passed to @ref fhost_wpa_enable_network if
 *                           @p enable is true.
 *
 * @return 0 on success, <0 if error occurred.
 ****************************************************************************************
 */
int fhost_wpa_create_network(int fhost_vif_idx, char *net_cfg, bool enable, int timeout_ms);

/**
 ****************************************************************************************
 * @brief Enable a wpa_supplicant network
 *
 * Enabling a network means that wpa_supplicant will try to connect to the AP configured
 * in this network.
 * The function is blocking until the connection to the network is completed (or timeout
 * is reached).
 * If @p timeout_ms is <0 then the function won't timeout and if it is 0 then the function
 * returns immediately after enabling the network with 0 exit code.
 * The network must have been created with @ref fhost_wpa_create_network first.
 *
 * @param[in] fhost_vif_idx  Index of the FHOST interface.
 * @param[in] timeout_ms     Timeout, in ms, until connection is considered as failed.
 *                           (<0 wait forever, 0 don't wait)
 *
 * @return 0 on success, <0 if error occurred.
 ****************************************************************************************
 */
int fhost_wpa_enable_network(int fhost_vif_idx, int timeout_ms);

/**
 ****************************************************************************************
 * @brief Disable a wpa_supplicant network
 *
 * Disabling a network means that wpa_supplicant will disconnect from the AP and will no
 * longer try to connect.
 * The function is blocking until the connection to the network is completed.
 * The network must have been created with @ref fhost_wpa_create_network first.
 *
 * @param[in] fhost_vif_idx  Index of the FHOST interface.
 *
 * @return 0 on success, <0 if error occurred.
 ****************************************************************************************
 */
int fhost_wpa_disable_network(int fhost_vif_idx);

int fhost_wpa_set_mgmt_rx_filter(int fhost_vif_idx, uint32_t filter);
int fhost_wpa_disconnect_network(int fhost_vif_idx);
int fhost_wpa_reconnect_network(int fhost_vif_idx, int timeout_ms);
int fhost_wpa_stop_ap(int fhost_vif_idx);
int fhost_wpa_disassociate_sta(int fhost_vif_idx, struct mac_addr *macaddr);
int fhost_wpa_wps(int fhost_vif_idx, bool enable, int timeout_ms);
int fhost_wpa_switch_channel(int fhost_vif_idx, uint32_t frequency);

int fhost_bss_flush(int fhost_vif_idx);

void wpas_data_save(void);
void wpas_data_restore(void);

#endif // _WIFI_HOST_WPA_H
